#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include "module.h"
#include "link_list.h"

#define MAX_SIZE 50

int do_register(int socketfd);
int do_login(int socketfd, user_obj_t *user_obj);
void do_after_login(int socketfd, user_obj_t *user_obj);
int do_create_account(int socketfd, user_obj_t *user, func_obj_t *func_obj);
int create_account(int socketfd, role_obj_t *role);
int do_edit_account(int socketfd);
int do_delete_account(int socketfd);
void create_admin(int socketfd);
void create_user(int socketfd);

int main(int argc, const char *argv[])
{
	if(argc != 3){
		printf("cmd + ip + port\n");
		exit(1);
	}

	int socketfd = socket(AF_INET, SOCK_STREAM, 0);
	if(-1 == socketfd){
		perror("fail to socket\n");
		exit(-1);
	}
	struct sockaddr_in serveraddr;
	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(atoi(argv[2]));
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);

	int ret = connect(socketfd, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr_in));
	if(-1 == ret){
		printf("server %s:%d fail to connect!!!\n", inet_ntoa(serveraddr.sin_addr), ntohs(serveraddr.sin_port));
		exit(1);
	}

	int input_opt_type = 0;//输入的操作选项
	user_obj_t user_obj;
	bzero(&user_obj, sizeof(user_obj_t));

	while(1){
		printf("**********************************\n");
		printf("**** 0:quit 1:register 2:login ***\n");
		printf("**********************************\n");
		printf(">>>>>input option:");
		scanf("%d", &input_opt_type);
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);

		switch(input_opt_type){
			case 0:
				printf("client quit...\n");
				close(socketfd);
				return 0;
			case 1:
				do_register(socketfd);
				break;
			case 2:
				ret = do_login(socketfd, &user_obj);
				if(0 == ret){
					do_after_login(socketfd, &user_obj);
					printf("logout...\n");
					bzero(&user_obj, sizeof(user_obj_t));
				}
				break;
			default:
				printf("Please enter the correct option!!!\n");
		}
	}
	close(socketfd);

	return 0;
}

int do_register(int socketfd){
	user_obj_t user;
	printf("*********** REGISTER *************\n");
	printf(">>>>>input username:");
	fgets(user.username, NAME_SIZE, stdin);
	if('\n' != user.username[strlen(user.username) - 1]){
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
	}
	user.username[strlen(user.username) - 1] = '\0';
	printf("username is:%s\n", user.username);

	printf(">>>>>input passwd:");
	fgets(user.passwd, PASSWD_SIZE, stdin);
	if('\n' != user.passwd[strlen(user.passwd) - 1]){
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
	}
	user.passwd[strlen(user.passwd) - 1] = '\0';
	printf("passwd is:%s\n", user.passwd);

	msg_t msg;
	msg.opt_type = OPT_TYPE_REGISTER;

	int write_count = 0;
	int read_count = 0;

	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		perror("fail to send msg to server!!!");
		return -1;
	}
	write_count = write(socketfd, &user, sizeof(user_obj_t));
	if(-1 == write_count){
		perror("fail to send user to server!!!");
		return -1;
	}

	read_count = read(socketfd, &msg, sizeof(msg_t));
	if(-1 == read_count){
		perror("fail to read msg from server!!!");
		return -1;
	}

	if(0 == read_count){
		perror("server closed connect!!!");
		return -1;
	}

	if(OPT_RESULT_FAIL == msg.opt_result){
		printf("fail to register, username is exist!!!\n");
		return -1;
	}

	if(OPT_RESULT_SYS_ERR == msg.opt_result){
		printf("server error, please try again!!!\n");
		return -1;
	}
	
	printf("****** register successfully *****\n");
	return 0;
}

int do_login(int socketfd, user_obj_t *user){
	bzero(user, sizeof(user_obj_t));

	printf("************** LOGIN *************\n");
	printf(">>>>>input username:");
	fgets(user->username, NAME_SIZE, stdin);
	if('\n' != user->username[strlen(user->username) - 1]){
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
	}
	user->username[strlen(user->username) - 1] = '\0';
	printf("username is:%s\n", user->username);

	printf(">>>>>input passwd:");
	fgets(user->passwd, PASSWD_SIZE, stdin);
	if('\n' != user->passwd[strlen(user->passwd) - 1]){
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
	}
	user->passwd[strlen(user->passwd) - 1] = '\0';
	printf("passwd is:%s\n", user->passwd);


	msg_t msg;
	msg.opt_type = OPT_TYPE_LOGIN;

	int write_count = 0;
	int read_count = 0;

	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		perror("fail to send msg to server!!!");
		return -1;
	}
	write_count = write(socketfd, user, sizeof(user_obj_t));
	if(-1 == write_count){
		perror("fail to send user to server!!!\n");
		return -1;
	}

	read_count = read(socketfd, &msg, sizeof(msg_t));
	if(-1 == read_count){
		perror("fail to read msg from server!!!");
		return -1;
	}
	if(0 == read_count){
		printf("server closed connect!!!\n");
		return -1;
	}
	if(OPT_RESULT_FAIL == msg.opt_result){
		printf("username or passwd error!!!\n");
		return -1;
	}
	if(OPT_RESULT_SYS_ERR == msg.opt_result){
		printf("server error!!!\n");
		return -1;
	}

	read_count = read(socketfd, user, sizeof(user_obj_t));
	if(-1 == read_count){
		perror("fail to read user from server!!!");
		return -1;
	}
	if(0 == read_count){
		printf("server closed connect!!!\n");
		return -1;
	}


	printf("******* login successfully *******\n");
	return 0;
}

void do_after_login(int socketfd, user_obj_t *user){
	int input_opt_type = 0;
	linklist_t *list = create_linklist();

	int write_count = 0;
	int read_count = 0;

	//获取功能菜单数量
	int rows = 0;
	read_count = read(socketfd, &rows, sizeof(int));
	if(-1 == read_count){
		printf("fail to read from server!!!\n");
	}else{
		//获取所有的功能菜单信息，保存到链表中
		while(rows > 0){
			func_obj_t *func_obj = (func_obj_t *)malloc(sizeof(func_obj_t));
			//接收功能信息
			read_count = read(socketfd, func_obj, sizeof(func_obj_t));
			if(-1 == read_count){
				printf("fail to read from server!!!\n");
			}else{
				//printf("%d\t%s\t%s\t%d\n", func_obj->id, func_obj->func_name, func_obj->func_desc, func_obj->func_parent);
				//插入链表
				insert_list(list, 0, (void *)func_obj);
			}

			rows--;
		}
	}
	
	
	reverse_linklist(list);
	while(1){
		//打印功能菜单
		printf("**********************************\n");
		printf("********* select option **********\n");
		printf("**********************************\n");
		printf("********* 0:logout\n");
		int i = 1;
		linklist_t *p = list;
		while(NULL != p->next){
			linklist_t *node = p->next;
			func_obj_t *func_obj = (func_obj_t *)node->data;
			printf("****** %d:%s\n", i, func_obj->func_name);
			//printf("%d\t%s\t%s\t%d\n", func_obj->id, func_obj->func_name, func_obj->func_desc, func_obj->func_parent);

			p = node;
			i++;
		}
		printf("**********************************\n");
		printf("******* select option end ********\n");


		printf(">>>>>input option:");
		scanf("%d", &input_opt_type);
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
		if(input_opt_type < 0 || input_opt_type >= i){
			printf("Please enter the correct option!!!\n");
			continue;
		}
		if(0 == input_opt_type){
			//logout
			linklist_t *p = list;
			while(NULL != p->next){
				linklist_t *node = p->next;
				free(node->data);

				p = node;
			}

			destroy_linklist(&list);
			return;
		}
		
		func_obj_t *func_obj = (func_obj_t *)get_list_node_data(list, input_opt_type);
		printf("%d\t%s\t%s\t%d\n", func_obj->id, func_obj->func_name, func_obj->func_desc, func_obj->func_parent);
		
		switch(func_obj->id){
			case FUNC_CREATE_ACCOUNT:
				do_create_account(socketfd, user, func_obj);
				break;
			case FUNC_EDITE_ACCOUNT:
				do_edit_account(socketfd);
				break;
			case FUNC_DELETE_ACCOUNT:
				do_delete_account(socketfd);
				break;
			case FUNC_USER_INFO:
				break;
			case FUNC_EDITE_INFO:
				break;
			case FUNC_UPLOAD:
				break;
			case FUNC_DOWNLOAD:
				break;
			case FUNC_DELETE_FILE:
				break;
			case FUNC_UPLOAD_FILE_LIST:
				break;
			default:
				printf("Error func!!!\n");
		}
	}
}

int do_delete_account(int socketfd){
	printf("************** DELETE ACCOUNT *************\n");
	msg_t msg;
	msg.opt_type = FUNC_DELETE_ACCOUNT;

	int write_count = 0;
	int read_count = 0;
	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		printf("fail to send msg to server!!!\n");
		return -1;
	}

	linklist_t *list = create_linklist();

	//获取功能菜单数量
	int rows = 0;
	read_count = read(socketfd, &rows, sizeof(int));
	if(-1 == read_count){
		printf("fail to read user list from server!!!\n");
	}else{
		//获取所有的功能菜单信息，保存到链表中
		while(rows > 0){
			user_obj_t *user_obj = (user_obj_t *)malloc(sizeof(user_obj_t));
			//接收功能信息
			read_count = read(socketfd, user_obj, sizeof(user_obj_t));
			if(-1 == read_count){
				printf("fail to read from server!!!\n");
			}else{
				//printf("%d\t%s\t%s\t%d\n", func_obj->id, func_obj->func_name, func_obj->func_desc, func_obj->func_parent);
				//插入链表
				insert_list(list, 0, (void *)user_obj);
			}

			rows--;
		}
	}
	reverse_linklist(list);
	
	//打印功能菜单
	
	int input_opt_type = 0;
	while(1){
		printf("**********************************\n");
		printf("********* select user **********\n");
		printf("**********************************\n");
		printf("********* 0:quit\n");
		int i = 1;
		linklist_t *p = list;
		while(NULL != p->next){
			linklist_t *node = p->next;
			user_obj_t *user_obj = (user_obj_t *)node->data;
			printf("****** %d:%s\n", i, user_obj->username);
			//printf("%d\t%s\t%s\t%d\n", func_obj->id, func_obj->func_name, func_obj->func_desc, func_obj->func_parent);

			p = node;
			i++;
		}
		printf("**********************************\n");
		printf("******* select option end ********\n");


		printf(">>>>>input option:");
		scanf("%d", &input_opt_type);
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
		if(input_opt_type < 0 || input_opt_type >= i){
			printf("Please enter the correct option!!!\n");
			continue;
		}
		break;
	}
	if(0 == input_opt_type){
		//logout
		linklist_t *p = list;
		while(NULL != p->next){
			linklist_t *node = p->next;
			free(node->data);

			p = node;
		}

		destroy_linklist(&list);
		return;
	}
	user_obj_t *user_obj = (user_obj_t *)get_list_node_data(list, input_opt_type);
	printf("%d\t%s\t%s\n", user_obj->id, user_obj->username, user_obj->passwd);
	
	bzero(&msg, sizeof(msg_t));
	msg.opt_type = OPT_DELETE_ACCOUNT;


	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		perror("fail to send msg to server!!!");
		return -1;
	}
	write_count = write(socketfd, user_obj, sizeof(user_obj_t));
	if(-1 == write_count){
		perror("fail to send user to server!!!");
		return -1;
	}

	read_count = read(socketfd, &msg, sizeof(msg_t));
	if(-1 == read_count){
		perror("fail to read msg from server!!!");
		return -1;
	}

	if(0 == read_count){
		perror("server closed connect!!!");
		return -1;
	}

	if(OPT_RESULT_FAIL == msg.opt_result){
		printf("fail to update passwd !!!\n");
		return -1;
	}

	if(OPT_RESULT_SYS_ERR == msg.opt_result){
		printf("server error, please try again!!!\n");
		return -1;
	}
	
	return 0;
}

int do_edit_account(int socketfd){
	printf("************** EDITE ACCOUNT *************\n");
	msg_t msg;
	msg.opt_type = FUNC_EDITE_ACCOUNT;

	int write_count = 0;
	int read_count = 0;
	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		printf("fail to send msg to server!!!\n");
		return -1;
	}
	
	linklist_t *list = create_linklist();

	//获取功能菜单数量
	int rows = 0;
	read_count = read(socketfd, &rows, sizeof(int));
	if(-1 == read_count){
		printf("fail to read user list from server!!!\n");
	}else{
		//获取所有的功能菜单信息，保存到链表中
		while(rows > 0){
			user_obj_t *user_obj = (user_obj_t *)malloc(sizeof(user_obj_t));
			//接收功能信息
			read_count = read(socketfd, user_obj, sizeof(user_obj_t));
			if(-1 == read_count){
				printf("fail to read from server!!!\n");
			}else{
				//printf("%d\t%s\t%s\t%d\n", func_obj->id, func_obj->func_name, func_obj->func_desc, func_obj->func_parent);
				//插入链表
				insert_list(list, 0, (void *)user_obj);
			}

			rows--;
		}
	}
	
	
	reverse_linklist(list);
	
	//打印功能菜单
	
	int input_opt_type = 0;
	while(1){
		printf("**********************************\n");
		printf("********* select user **********\n");
		printf("**********************************\n");
		printf("********* 0:quit\n");
		int i = 1;
		linklist_t *p = list;
		while(NULL != p->next){
			linklist_t *node = p->next;
			user_obj_t *user_obj = (user_obj_t *)node->data;
			printf("****** %d:%s\n", i, user_obj->username);
			//printf("%d\t%s\t%s\t%d\n", func_obj->id, func_obj->func_name, func_obj->func_desc, func_obj->func_parent);

			p = node;
			i++;
		}
		printf("**********************************\n");
		printf("******* select option end ********\n");


		printf(">>>>>input option:");
		scanf("%d", &input_opt_type);
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
		if(input_opt_type < 0 || input_opt_type >= i){
			printf("Please enter the correct option!!!\n");
			continue;
		}
		break;
	}
	if(0 == input_opt_type){
		//logout
		linklist_t *p = list;
		while(NULL != p->next){
			linklist_t *node = p->next;
			free(node->data);

			p = node;
		}

		destroy_linklist(&list);
		return;
	}

	user_obj_t *user_obj = (user_obj_t *)get_list_node_data(list, input_opt_type);
	printf("%d\t%s\t%s\n", user_obj->id, user_obj->username, user_obj->passwd);
	
	printf("****************** update passwd ******************\n");
	printf(">>>>>input passwd:");
	fgets(user_obj->passwd, PASSWD_SIZE, stdin);
	if('\n' != user_obj->passwd[strlen(user_obj->passwd) - 1]){
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
	}
	user_obj->passwd[strlen(user_obj->passwd) - 1] = '\0';
	printf("passwd is:%s\n", user_obj->passwd);

	bzero(&msg, sizeof(msg_t));
	msg.opt_type = OPT_UPDATE_PASSWORD;


	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		perror("fail to send msg to server!!!");
		return -1;
	}
	write_count = write(socketfd, user_obj, sizeof(user_obj_t));
	if(-1 == write_count){
		perror("fail to send user to server!!!");
		return -1;
	}

	read_count = read(socketfd, &msg, sizeof(msg_t));
	if(-1 == read_count){
		perror("fail to read msg from server!!!");
		return -1;
	}

	if(0 == read_count){
		perror("server closed connect!!!");
		return -1;
	}

	if(OPT_RESULT_FAIL == msg.opt_result){
		printf("fail to update passwd !!!\n");
		return -1;
	}

	if(OPT_RESULT_SYS_ERR == msg.opt_result){
		printf("server error, please try again!!!\n");
		return -1;
	}

	return 0;
}


int do_create_account(int socketfd, user_obj_t *user, func_obj_t *func_obj){
	printf("************** CREATE ACCOUNT *************\n");
	msg_t msg;
	msg.opt_type = FUNC_CREATE_ACCOUNT;

	int write_count = 0;
	int read_count = 0;
	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		printf("fail to send msg to server!!!\n");
		return -1;
	}
	write_count = write(socketfd, user, sizeof(user_obj_t));
	if(-1 == write_count){
		printf("fail to send user to server!!!\n");
		return -1;
	}
	write_count = write(socketfd, func_obj, sizeof(func_obj_t));
	if(-1 == write_count){
		printf("fail to send func_obj to server!!!\n");
		return -1;
	}
	

	linklist_t *list = create_linklist();


	//获取功能菜单数量
	int rows = 0;
	read_count = read(socketfd, &rows, sizeof(int));
	if(-1 == read_count){
		printf("fail to read from server!!!\n");
	}else{
		//获取所有的功能菜单信息，保存到链表中
		while(rows > 0){
			func_obj_t *func_obj = (func_obj_t *)malloc(sizeof(func_obj_t));
			//接收功能信息
			read_count = read(socketfd, func_obj, sizeof(func_obj_t));
			if(-1 == read_count){
				printf("fail to read from server!!!\n");
			}else{
				//printf("%d\t%s\t%s\t%d\n", func_obj->id, func_obj->func_name, func_obj->func_desc, func_obj->func_parent);
				//插入链表
				insert_list(list, 0, (void *)func_obj);
			}

			rows--;
		}
	}
	
	
	reverse_linklist(list);
	while(1){
		//打印功能菜单
		printf("**********************************\n");
		printf("********* select option **********\n");
		printf("**********************************\n");
		printf("********* 0:quit\n");
		int i = 1;
		linklist_t *p = list;
		while(NULL != p->next){
			linklist_t *node = p->next;
			func_obj_t *func_obj = (func_obj_t *)node->data;
			printf("****** %d:%s\n", i, func_obj->func_name);
			//printf("%d\t%s\t%s\t%d\n", func_obj->id, func_obj->func_name, func_obj->func_desc, func_obj->func_parent);

			p = node;
			i++;
		}
		printf("**********************************\n");
		printf("******* select option end ********\n");


		printf(">>>>>input option:");
		int input_opt_type = 0;
		scanf("%d", &input_opt_type);
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
		if(input_opt_type < 0 || input_opt_type >= i){
			printf("Please enter the correct option!!!\n");
			continue;
		}
		if(0 == input_opt_type){
			//logout
			linklist_t *p = list;
			while(NULL != p->next){
				linklist_t *node = p->next;
				free(node->data);

				p = node;
			}

			destroy_linklist(&list);
			return;
		}
		
		func_obj_t *func_obj = (func_obj_t *)get_list_node_data(list, input_opt_type);
		printf("%d\t%s\t%s\t%d\n", func_obj->id, func_obj->func_name, func_obj->func_desc, func_obj->func_parent);
		
		switch(func_obj->id){
			case FUNC_CREATE_ADMIN_ACCOUNT:
				create_admin(socketfd);
				break;
			case FUNC_CREATE_USER_ACCOUNT:
				create_user(socketfd);
				break;
			default:
				printf("Error func!!!\n");
		}

	}
}

void create_user(int socketfd){
	printf("*********** CREATE USER ACCOUNT **********\n");

	role_obj_t role;
	role.id = ROLE_USER_ID;

	int ret = create_account(socketfd, &role);
	if(0 == ret){
		printf("******** create account successfully *******\n");
	}else{
		printf("******** fail to create account *******\n");
	}

}

void create_admin(int socketfd){

	printf("*********** CREATE ADMIN ACCOUNT **********\n");
	role_obj_t role;
	role.id = ROLE_ADMIN_ID;

	int ret = create_account(socketfd, &role);
	if(0 == ret){
		printf("******** create account successfully *******\n");
	}else{
		printf("******** fail to create account *******\n");
	}

}

int create_account(int socketfd, role_obj_t *role){

	user_obj_t user;
	
	printf(">>>>>input username:");
	fgets(user.username, NAME_SIZE, stdin);
	if('\n' != user.username[strlen(user.username) - 1]){
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
	}
	user.username[strlen(user.username) - 1] = '\0';
	printf("username is:%s\n", user.username);

	printf(">>>>>input passwd:");
	fgets(user.passwd, PASSWD_SIZE, stdin);
	if('\n' != user.passwd[strlen(user.passwd) - 1]){
		char ch;
		while((ch = getchar()) != '\n' && ch != EOF);
	}
	user.passwd[strlen(user.passwd) - 1] = '\0';
	printf("passwd is:%s\n", user.passwd);

	msg_t msg;
	msg.opt_type = FUNC_CREATE_ADMIN_ACCOUNT;

	int write_count = 0;
	int read_count = 0;

	write_count = write(socketfd, &msg, sizeof(msg_t));
	if(-1 == write_count){
		perror("fail to send msg to server!!!");
		return -1;
	}
	write_count = write(socketfd, &user, sizeof(user_obj_t));
	if(-1 == write_count){
		perror("fail to send user to server!!!");
		return -1;
	}

	write_count = write(socketfd, role, sizeof(role_obj_t));
	if(-1 == write_count){
		perror("fail to send user to server!!!");
		return -1;
	}

	read_count = read(socketfd, &msg, sizeof(msg_t));
	if(-1 == read_count){
		perror("fail to read msg from server!!!");
		return -1;
	}

	if(0 == read_count){
		perror("server closed connect!!!");
		return -1;
	}

	if(OPT_RESULT_FAIL == msg.opt_result){
		printf("fail to create account, username is exist!!!\n");
		return -1;
	}

	if(OPT_RESULT_SYS_ERR == msg.opt_result){
		printf("server error, please try again!!!\n");
		return -1;
	}

	return 0;
}
